package schemax

import (
	"gitee.com/zhongguo168a/gocodes/datax"
	"gitee.com/zhongguo168a/gocodes/datax/schemax/basickind"
	"gitee.com/zhongguo168a/gocodes/myx/errorx"
)

// 如果是数字，会转化成正确的类型
func CheckType(valType IType, val interface{}) (err error) {
	switch typ := valType.(type) {
	case *EnumType:
		err = checkEnumType(typ, val)
	case *BasicType:
		err = checkBasicType(typ, val)

	}
	return err
}

// 如果是数字，会转化成正确的类型
func CheckObject(obj datax.M, decl *ClassDecl) (err error) {
	return checkObject(obj, decl)
}

// todo: 不完整
func checkObject(obj datax.M, decl *ClassDecl) error {
	for _, field := range decl.GetAllField() {
		fname := field.Name
		val, has := obj[fname]
		if !has && val == nil {
			continue
		}
		var err error
		switch typ := field.Type.(type) {
		case *ClassType:
			typDecl := GetDeclByKey(typ.Decl)
			if typDecl == nil {
				return errorx.New("decl not found", datax.M{"name": fname, "class": typ.Decl})
			}
			mval, ok := val.(map[string]interface{})
			if ok == false {
				return errorx.New("map value not map[string]interface{}", datax.M{"name": fname})
			}
			classErr := checkObject(mval, typDecl.(*ClassDecl))
			if classErr != nil {
				return errorx.Wrap(err, "check class", datax.M{"name": fname, "class": typ.Decl})
			}
		case *MapType:
		case *EnumType:
			err = checkEnumType(typ, val)
		case *BasicType:
			err = checkBasicType(typ, val)
		}

		if err != nil {
			return errorx.Wrap(err, "check field", datax.M{"name": fname})
		}
	}

	return nil
}

func checkEnumType(typ *EnumType, val interface{}) error {
	iedecl := GetDeclByKey(typ.Decl)
	if iedecl == nil {
		return errorx.New("decl not found", datax.M{"decl": typ.Decl})
	}
	edecl := iedecl.(*EnumDecl)
	kind := basickind.Kind(edecl.Kind)
	switch kind {
	case basickind.Int8:
		fallthrough
	case basickind.Int16:
		fallthrough
	case basickind.Int32:
		fallthrough
	case basickind.Int64:
		fallthrough
	case basickind.Uint8:
		fallthrough
	case basickind.Uint16:
		fallthrough
	case basickind.Uint32:
		fallthrough
	case basickind.Uint64:
		switch val.(type) {
		case int:
		default:
			return errorx.New("not number")
		}
	case basickind.String:
		switch val.(type) {
		case string:
		default:
			return errorx.New("not string")
		}
	}

	return nil
}

func checkBasicType(typ *BasicType, val interface{}) error {
	switch typ.Kind {
	case basickind.Bool:
		switch val.(type) {
		case bool:
		default:
			return errorx.New("not bool")
		}
	case basickind.Int8:
		fallthrough
	case basickind.Int16:
		fallthrough
	case basickind.Int32:
		fallthrough
	case basickind.Int64:
		fallthrough
	case basickind.Uint8:
		fallthrough
	case basickind.Uint16:
		fallthrough
	case basickind.Uint32:
		fallthrough
	case basickind.Uint64:
		switch val.(type) {
		case int:
		case float64:
		case string:
		default:
			return errorx.New("not number")
		}
	case basickind.Float32:
		fallthrough
	case basickind.Float64:
		switch val.(type) {
		case int:
		case float64:
		default:
		}
	case basickind.String:
		switch val.(type) {
		case string:
		default:
			return errorx.New("not string")
		}
	}

	return nil
}
